home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / drivers / char / atari_MFPser.c next >
Encoding:
C/C++ Source or Header  |  1994-06-08  |  14.0 KB  |  516 lines

  1.  
  2.  
  3. /*
  4.  * drivers/char/atari_MFPser.c: Atari MFP serial ports implementation
  5.  *
  6.  * Copyright 1994 Roman Hodek
  7.  *   EMail: rnhodek@cip.informatik.uni-erlangen.de (Internet)
  8.  *      or: Roman_Hodek@n.maus.de (MausNet, NO mail > 16 KB!)
  9.  * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o
  10.  * 
  11.  * This file is subject to the terms and conditions of the GNU General Public
  12.  * License.  See the file README.legal in the main directory of this archive
  13.  * for more details.
  14.  *
  15.  */
  16.  
  17.  
  18. /* This file implements the MFP serial ports. These come in two
  19.  * flavors: with or without control lines (RTS, CTS, DTR, ...). They
  20.  * are distinguished by having two different types, MFP_CTRL and
  21.  * MFP_BARE, resp. Most of the low-level functions are the same for
  22.  * both, but some differ.
  23.  *
  24.  * Note that some assumptions are made about where to access the
  25.  * control lines. If the port type is MFP_CTRL, the input lines (CTS
  26.  * and DCD) are assumed to be in the MFP GPIP register, bits 1 and 2.
  27.  * The output lines (DTR and RTS) have to be in the Soundchip Port A,
  28.  * bits 3 and 4. This is the standard ST/TT assigment. If Atari will
  29.  * build a serial port in future, that uses other registers, you have
  30.  * to rewrite this code. But if the port type is MFP_BARE, no such
  31.  * assumptions are necessary. All registers needed are fixed by the
  32.  * MFP hardware. The only parameter is the MFP base address. This is
  33.  * used to implement Serial1 for the TT and the (not connected) MFP
  34.  * port of the Falcon.
  35.  * 
  36.  */
  37.  
  38. #include <linux/types.h>
  39. #include <linux/sched.h>
  40. #include <linux/interrupt.h>
  41. #include <linux/errno.h>
  42. #include <linux/tty.h>
  43. #include <linux/termios.h>
  44. #include <linux/atarihw.h>
  45. #include <linux/atariints.h>
  46.  
  47. #include "atari_serial.h"
  48. #include "atari_MFPser.h"
  49.  
  50.  
  51.  
  52. /***************************** Prototypes *****************************/
  53.  
  54. static void MFPser_rx_int( struct intframe *fp, struct async_struct *info );
  55. static void MFPser_rxerr_int( struct intframe *fp, struct async_struct
  56.                               *info );
  57. static void MFPser_tx_int( struct intframe *fp, struct async_struct *info );
  58. static void MFPctrl_dcd_int( struct intframe *fp, struct async_struct *info
  59.                              );
  60. static void MFPctrl_cts_int( struct intframe *fp, struct async_struct *info
  61.                              );
  62. static void MFPser_init( struct async_struct *info );
  63. static void MFPser_deinit( struct async_struct *info, int leave_dtr );
  64. static void MFPser_enab_tx_int( struct async_struct *info, int enab_flag );
  65. static int MFPser_check_custom_divisor( struct async_struct *info, int
  66.                                         divisor );
  67. static void MFPser_change_speed( struct async_struct *info );
  68. static void MFPser_restart( struct async_struct *info, int ch );
  69. static void MFPctrl_throttle( struct async_struct *info, int status );
  70. static void MFPbare_throttle( struct async_struct *info, int status );
  71. static void MFPser_set_break( struct async_struct *info, int break_flag );
  72. static void MFPser_get_serial_info( struct async_struct *info, struct
  73.                                     serial_struct *retinfo );
  74. static unsigned int MFPctrl_get_modem_info( struct async_struct *info );
  75. static unsigned int MFPbare_get_modem_info( struct async_struct *info );
  76. static int MFPctrl_set_modem_info( struct async_struct *info, int new_dtr,
  77.                                    int new_rts );
  78. static int MFPbare_set_modem_info( struct async_struct *info, int new_dtr,
  79.                                    int new_rts );
  80.  
  81. /************************* End of Prototypes **************************/
  82.  
  83.  
  84.  
  85. /* SERIALSWITCH structures for MFP ports
  86.  * Most functions are common to MFP ports with or without control lines
  87.  */
  88.  
  89. static SERIALSWITCH MFPctrl_switch = {
  90.     MFPser_init, MFPser_deinit, MFPser_enab_tx_int,
  91.     MFPser_check_custom_divisor, MFPser_change_speed,
  92.     MFPser_restart, MFPctrl_throttle, MFPser_set_break,
  93.     MFPser_get_serial_info, MFPctrl_get_modem_info,
  94.     MFPctrl_set_modem_info, NULL
  95. };
  96.  
  97.  
  98. static SERIALSWITCH MFPbare_switch = {
  99.     MFPser_init, MFPser_deinit, MFPser_enab_tx_int,
  100.     MFPser_check_custom_divisor, MFPser_change_speed,
  101.     MFPser_restart, MFPbare_throttle, MFPser_set_break,
  102.     MFPser_get_serial_info, MFPbare_get_modem_info,
  103.     MFPbare_set_modem_info, NULL
  104. };
  105.  
  106. /* MFP Timer Modes divided by 2 (this already done in the BAUD_BASE */
  107. int MFP_timer_modes[] = { 2, 5, 8, 25, 32, 50, 100 };
  108.  
  109. /* Divisors for standard speeds */
  110. int MFP_baud_table[15] = {
  111.     /* B0     */ 0,
  112.     /* B50    */ 768,
  113.     /* B75    */ 512,
  114.     /* B110   */ 350, /* really 109.71 bps */
  115.     /* B134      */ 286, /* really 134.27 bps */
  116.     /* B150      */ 256,
  117.     /* B200      */ 192,
  118.     /* B300      */ 128,
  119.     /* B600      */ 64,
  120.     /* B1200  */ 32,
  121.     /* B1800  */ 21,
  122.     /* B2400  */ 16,
  123.     /* B4800  */ 8,
  124.     /* B9600  */ 4,
  125.     /* B19200 */ 2
  126. };
  127.     
  128.  
  129. void atari_init_MFPser( struct async_struct *info, SERTYPE type,
  130.                         int tt_flag, void *ri_addr,
  131.                         unsigned char ri_bitno, unsigned char ri_active )
  132.  
  133. {    
  134.     /* set ISRs, but don't enable interrupts yet (done in init()) */
  135.     add_isr( tt_flag ? IRQ_TT_MFP_SEREMPT : IRQ_MFP_SEREMPT,
  136.              (isrfunc)MFPser_tx_int, 0, info );
  137.     add_isr( tt_flag ? IRQ_TT_MFP_RECFULL : IRQ_MFP_RECFULL,
  138.              (isrfunc)MFPser_rx_int, 0, info );
  139.     add_isr( tt_flag ? IRQ_TT_MFP_RECERR : IRQ_MFP_RECERR,
  140.              (isrfunc)MFPser_rxerr_int, 0, info );
  141.     /* Tx_err interrupt unused (it signals only that the Tx shift reg
  142.      * is empty)
  143.      */
  144.     
  145.     if (type == MFP_CTRL && !tt_flag) {
  146.         add_isr( IRQ_MFP_DCD, (isrfunc)MFPctrl_dcd_int, 0, info );
  147.         add_isr( IRQ_MFP_CTS, (isrfunc)MFPctrl_cts_int, 0, info );
  148.         /* clear RTS and DTR */
  149.         GIACCESS( GI_RTS | GI_DTR );
  150.     }
  151.     
  152.     info->type            = type;
  153.     info->base            = tt_flag ? &tt_mfp : &mfp;
  154.     info->RI.addr         = (volatile unsigned char *)ri_addr;
  155.     info->RI.bitno        = ri_bitno;
  156.     info->RI.active_state = ri_active;
  157.     info->sw              = (type == MFP_CTRL) ? &MFPctrl_switch :
  158.                                                  &MFPbare_switch;
  159.  
  160.     currMFP(info)->rcv_stat  = 0;    /* disable Rx */
  161.     currMFP(info)->trn_stat  = 0;    /* disable Tx */
  162. }
  163.  
  164.  
  165. static void MFPser_rx_int( struct intframe *fp, struct async_struct *info )
  166.  
  167. {    int        ch, stat, err;
  168.     
  169.     stat = currMFP(info)->rcv_stat;
  170.     ch   = currMFP(info)->usart_dta;
  171.     /* Frame Errors don't cause a RxErr IRQ! */
  172.     err  = (stat & RSR_FRAME_ERR) ? TTY_FRAME : 0;
  173.     
  174.     rs_put_char_to_queue( info, ch, err );
  175.     rs_rx_throttle_if_needed( info );
  176. }
  177.  
  178.  
  179. static void MFPser_rxerr_int( struct intframe *fp, struct async_struct *info )
  180.  
  181. {    int        ch, stat, err;
  182.     
  183.     stat = currMFP(info)->rcv_stat;
  184.     ch   = currMFP(info)->usart_dta; /* most probably junk data */
  185.  
  186.     if (stat & RSR_PARITY_ERR)
  187.         err = TTY_PARITY;
  188.     else if (stat & RSR_OVERRUN_ERR)
  189.         err = TTY_OVERRUN;
  190.     else if (stat & RSR_BREAK_DETECT)
  191.         err = TTY_BREAK;
  192.     else if (stat & RSR_FRAME_ERR)    /* should not be needed */
  193.         err = TTY_FRAME;
  194.     else
  195.         err = 0;
  196.  
  197.     rs_put_char_to_queue( info, ch, err );
  198.     rs_rx_throttle_if_needed( info );
  199. }
  200.  
  201.  
  202. static void MFPser_tx_int( struct intframe *fp, struct async_struct *info )
  203.  
  204. {    int        ch;
  205.  
  206.     if (currMFP(info)->trn_stat & TSR_BUF_EMPTY) {
  207.         if ((ch = rs_get_char_from_queue( info )) < 0) return;
  208.         currMFP(info)->usart_dta = ch;
  209.         rs_tx_wakeup_if_needed( info );
  210.     }
  211. }
  212.  
  213.  
  214. static void MFPctrl_dcd_int( struct intframe *fp, struct async_struct *info )
  215.  
  216. {    
  217.     /* Toggle active edge to get next change of DCD! */
  218.     currMFP(info)->active_edge ^= GPIP_DCD;
  219.  
  220.     rs_dcd_changed( info, !(currMFP(info)->par_dt_reg & GPIP_DCD) );
  221. }
  222.  
  223.  
  224. static void MFPctrl_cts_int( struct intframe *fp, struct async_struct *info )
  225.  
  226. {    
  227.     /* Toggle active edge to get next change of CTS! */
  228.     currMFP(info)->active_edge ^= GPIP_CTS;
  229.     
  230.     if (rs_cts_changed( info, !(currMFP(info)->par_dt_reg & GPIP_CTS) ))
  231.         /* Don't know yet if this is really necessary, or if a Tx
  232.          * IRQ is delivered anyway when turning on again.
  233.          */
  234.         MFPser_tx_int( fp, info );
  235. }
  236.  
  237.  
  238. static void MFPser_init( struct async_struct *info )
  239.  
  240. {    
  241.     /* base value for UCR */
  242.     currMFP(info)->usart_ctr = UCR_PARITY_OFF | UCR_ASYNC_1 |
  243.                                UCR_CHSIZE_8 | UCR_PREDIV;
  244.  
  245.     /* enable Rx and clear any error conditions */
  246.     currMFP(info)->rcv_stat = RSR_RX_ENAB;
  247.  
  248.     /* enable Tx */
  249.     currMFP(info)->trn_stat = TSR_TX_ENAB;
  250.  
  251.     /* enable Rx, RxErr and Tx interrupts */
  252.     currMFP(info)->int_en_a |= 0x1c;
  253.     currMFP(info)->int_mk_a |= 0x1c;
  254.  
  255.     if (info->type == MFP_CTRL) {
  256.  
  257.         /* set RTS and DTR (low-active!) */
  258.         GIACCESS( ~(GI_RTS | GI_DTR) );
  259.  
  260.         /* Set active edge of CTS and DCD signals depending on their
  261.          * current state.
  262.          * If the line status changes between reading the status and
  263.          * enabling the interrupt, this won't work :-( How could it be
  264.          * done better??
  265.          */
  266.         if (currMFP(info)->par_dt_reg & GPIP_CTS)
  267.             currMFP(info)->active_edge &= ~GPIP_CTS;
  268.         else
  269.             currMFP(info)->active_edge |= GPIP_CTS;
  270.         
  271.         if (currMFP(info)->par_dt_reg & GPIP_DCD)
  272.             currMFP(info)->active_edge &= ~GPIP_DCD;
  273.         else
  274.             currMFP(info)->active_edge |= GPIP_DCD;
  275.  
  276.         /* enable CTS and DCD interrupts */
  277.         currMFP(info)->int_en_b |= 0x06;
  278.         currMFP(info)->int_mk_b |= 0x06;
  279.     }
  280. }
  281.  
  282.  
  283. static void MFPser_deinit( struct async_struct *info, int leave_dtr )
  284.  
  285. {
  286.     /* disable Rx, RxErr and Tx interrupts */
  287.     currMFP(info)->int_en_a &= ~0x1c;
  288.  
  289.     if (info->type == MFP_CTRL) {
  290.         /* disable CTS and DCD interrupts */
  291.         currMFP(info)->int_en_b &= ~0x06;
  292.     }
  293.  
  294.     /* disable Rx and Tx */
  295.     currMFP(info)->rcv_stat = 0;
  296.     currMFP(info)->trn_stat = 0;
  297.     
  298.     /* wait for last byte to be completely shifted out */
  299.     while( !(currMFP(info)->trn_stat & TSR_LAST_BYTE_SENT) )
  300.         ;
  301.  
  302.     if (info->type == MFP_CTRL) {
  303.         /* drop RTS and DTR if required */
  304.         MFPser_RTSoff();
  305.         if (!leave_dtr)
  306.             MFPser_DTRoff();
  307.     }
  308.  
  309.     /* read Rx status and data to clean up */
  310.     (void)currMFP(info)->rcv_stat;
  311.     (void)currMFP(info)->usart_dta;
  312. }
  313.  
  314.  
  315. static void MFPser_enab_tx_int( struct async_struct *info, int enab_flag )
  316.  
  317. {
  318.     if (enab_flag)
  319.         currMFP(info)->int_en_a |= 0x04;
  320.     else
  321.         currMFP(info)->int_en_a &= ~0x04;
  322. }
  323.  
  324.  
  325. static int MFPser_check_custom_divisor( struct async_struct *info,
  326.                                         int divisor )
  327.  
  328. {    int        i;
  329.     
  330.     /* divisor must be a multiple of 2 or 5 (because of timer modes) */
  331.     if (divisor == 0 || ((divisor & 1) && (divisor % 5) != 0)) return( -1 );
  332.  
  333.     /* Determine what timer mode would be selected and look if the
  334.      * timer value would be greater than 256
  335.      */
  336.     for( i = sizeof(MFP_timer_modes)/sizeof(*MFP_timer_modes)-1; i >= 0; --i )
  337.         if (divisor % MFP_timer_modes[i] == 0) break;
  338.     if (i < 0) return( -1 ); /* no suitable timer mode found */
  339.  
  340.     return( divisor / MFP_timer_modes[i] <= 256 );
  341. }
  342.  
  343.  
  344. static void MFPser_change_speed( struct async_struct *info )
  345.  
  346. {    unsigned    cflag, baud, chsize, stopb, parity, aflags;
  347.     unsigned    div, timer_val;
  348.     int            timer_mode;
  349.     
  350.     if (!info->tty || !info->tty->termios) return;
  351.  
  352.     cflag  = info->tty->termios->c_cflag;
  353.     baud   = cflag & CBAUD;
  354.     chsize = cflag & CSIZE;
  355.     stopb  = cflag & CSTOPB;
  356.     parity = cflag & (PARENB | PARODD);
  357.     aflags = info->flags & ASYNC_SPD_MASK;
  358.  
  359.     if (baud == 15 && aflags == ASYNC_SPD_CUST)
  360.         div = info->custom_divisor;
  361.     else {
  362.         /* Maximum MFP speed is 19200 :-( */
  363.         if (baud > 14) baud = 14;
  364.         div = MFP_baud_table[baud];
  365.     }
  366.  
  367.     if (!div) {
  368.         /* speed == 0 -> drop DTR */
  369.         MFPser_DTRoff();
  370.         return;
  371.     }
  372.  
  373.     /* compute timer value and timer mode (garuateed to succeed, because
  374.      * the divisor was checked before by check_custom_divisor(), if it
  375.      * is used-supplied)
  376.      */
  377.     for( timer_mode = sizeof(MFP_timer_modes)/sizeof(*MFP_timer_modes)-1;
  378.          timer_mode >= 0; --timer_mode )
  379.         if (div % MFP_timer_modes[timer_mode] == 0) break;
  380.     timer_val = div / MFP_timer_modes[timer_mode];
  381.     
  382.     cli();
  383.     /* disable Rx and Tx while changing parameters */
  384.     currMFP(info)->rcv_stat = 0;
  385.     currMFP(info)->trn_stat = 0;
  386.  
  387.     /* stop timer D to set new timer value immediatly after re-enabling */
  388.     currMFP(info)->tim_ct_cd &= ~0x07;
  389.     currMFP(info)->tim_dt_d = timer_val;
  390.     currMFP(info)->tim_ct_cd |= (timer_mode+1);
  391.  
  392.     currMFP(info)->usart_ctr =
  393.         ( (parity & PARENB) ?
  394.               ((parity & PARODD) ? UCR_PARITY_ODD : UCR_PARITY_EVEN) :
  395.               UCR_PARITY_OFF ) |
  396.         ( chsize == CS5 ? UCR_CHSIZE_5 :
  397.           chsize == CS6 ? UCR_CHSIZE_6 :
  398.           chsize == CS7 ? UCR_CHSIZE_7 :
  399.                           UCR_CHSIZE_8 ) |
  400.         ( stopb ? UCR_ASYNC_2 : UCR_ASYNC_1 ) |
  401.         UCR_PREDIV;
  402.  
  403.     /* re-enable Rx and Tx */
  404.     currMFP(info)->rcv_stat = RSR_RX_ENAB;
  405.     currMFP(info)->trn_stat = TSR_TX_ENAB;
  406.     sti();
  407. }
  408.     
  409.     
  410. static void MFPser_restart( struct async_struct *info, int ch )
  411.  
  412. {
  413.     if (ch >= 0 && currMFP(info)->trn_stat & TSR_BUF_EMPTY)
  414.         currMFP(info)->usart_dta = ch;
  415. }
  416.  
  417.  
  418. static void MFPctrl_throttle( struct async_struct *info, int status )
  419.  
  420. {
  421.     if (status == TTY_THROTTLE_RQ_FULL)
  422.         MFPser_RTSoff();
  423.     else if (status == TTY_THROTTLE_RQ_AVAIL)
  424.         MFPser_RTSon();
  425. }
  426.  
  427.  
  428. static void MFPbare_throttle( struct async_struct *info, int status )
  429.  
  430. {
  431.     /* no-op */
  432. }
  433.  
  434.  
  435. static void MFPser_set_break( struct async_struct *info, int break_flag )
  436.  
  437. {
  438.     if (break_flag)
  439.         currMFP(info)->trn_stat |= TSR_SEND_BREAK;
  440.     else
  441.         currMFP(info)->trn_stat &= ~TSR_SEND_BREAK;
  442. }
  443.  
  444.  
  445. static void MFPser_get_serial_info( struct async_struct *info,
  446.                                    struct serial_struct *retinfo )
  447.  
  448. {
  449.     retinfo->baud_base = MFP_BAUD_BASE;
  450.     retinfo->custom_divisor = info->custom_divisor;
  451. }
  452.  
  453.  
  454. static unsigned int MFPctrl_get_modem_info( struct async_struct *info )
  455.  
  456. {    unsigned    gpip, gi;
  457.  
  458.     cli();
  459.     gpip = currMFP(info)->par_dt_reg;
  460.     gi   = GIACCESS( 0 );
  461.     sti();
  462.     
  463.     /* DSR is not connected on the Atari, assume it to be set;
  464.      * RI is tested by the RI bitpos field of info, because the RI is
  465.      * signalled at different ports on TT and Falcon
  466.      */
  467.     return( ((gi   & GI_RTS  ) ? TIOCM_RTS : 0) |
  468.             ((gi   & GI_DTR  ) ? TIOCM_DTR : 0) |
  469.             ((gpip & GPIP_DCD) ? TIOCM_CAR : 0) |
  470.             ((gpip & GPIP_CTS) ? TIOCM_CTS : 0) |
  471.             TIOCM_DSR |
  472.             (TEST_BITPOS( info->RI ) ? TIOCM_RNG : 0)
  473.           );
  474. }
  475.  
  476.  
  477. static unsigned int MFPbare_get_modem_info( struct async_struct *info )
  478.  
  479. {
  480.     return( TIOCM_RTS | TIOCM_DTR | TIOCM_CAR | TIOCM_CTS | TIOCM_DSR );
  481. }
  482.  
  483.  
  484. static int MFPctrl_set_modem_info( struct async_struct *info,
  485.                                    int new_dtr, int new_rts )
  486.  
  487. {
  488.     if (new_dtr == 0)
  489.         MFPser_DTRoff();
  490.     else if (new_dtr == 1)
  491.         MFPser_DTRon();
  492.  
  493.     if (new_rts == 0)
  494.         MFPser_RTSoff();
  495.     else if (new_rts == 1)
  496.         MFPser_RTSon();
  497.  
  498.     return( 0 );
  499. }
  500.  
  501.  
  502. static int MFPbare_set_modem_info( struct async_struct *info,
  503.                                    int new_dtr, int new_rts )
  504.  
  505. {
  506.     /* no-op */
  507.  
  508.     /* Is it right to return an error or should the attempt to change
  509.      * DTR or RTS be silently ignored?
  510.      */
  511.     return( -EINVAL );
  512. }
  513.  
  514.  
  515.  
  516.